package com.boot2.core.web.filter;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.boot2.core.cache.redis.RedisDao;
import com.boot2.core.constant.HttpConstant;
import com.boot2.core.dict.ErrorCode;
import com.boot2.core.exception.TokenValidationException;
import com.boot2.core.model.vo.Result;
import com.boot2.core.utils.JwtUtil;
import com.boot2.core.utils.ResultBuilder;
import com.boot2.core.utils.StringUtils;
import lombok.Data;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @author zhangweilin
 * @date 2018/6/13 8:27
 * @description: jwt认证
 */
@Data
@CommonsLog
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    /**
     * 有些url，是可或不获取用户信息，即也是可不要求经过token的，
     */
    public static final String isNeedToken = "_isNeedToken";


    private static final PathMatcher pathMatcher = new AntPathMatcher();
    /**
     * 受登录保护的路径,走过滤的条件之一
     */
    private String protectUrlPattern;
    /**
     * 排除需要登录的路径
     */
    private String exludeUrlPattern;
    /**
     * 不需要登录，但是需要走过滤，获取登录信息的路径,走过滤的条件之一
     */
    private List<String> noLoginNeedUserInfoList;

    private RedisDao redisDao;

    /**
     * 过滤策略，支持三种模式，纯redis,纯jwt, redisJwt(默认值)
     */
    private String filterStrategy = JwtUtil.FilterStrategy.redisJwt.name();

    public JwtAuthenticationFilter() {
    }

    public JwtAuthenticationFilter(String protectUrlPattern, String exludeUrlPattern, List<String> noLoginNeedUserInfoList) {
        this.protectUrlPattern = protectUrlPattern;
        this.noLoginNeedUserInfoList = noLoginNeedUserInfoList;
        this.exludeUrlPattern = exludeUrlPattern == null ? "" : exludeUrlPattern;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //在未配置的情况下，默认通过
        if (StringUtils.isEmpty(protectUrlPattern)) {
            filterChain.doFilter(request, response);
            return;
        }
        boolean isExlude = false;
        String requestUri = request.getServletPath();
//        log.info("requestUri: " + requestUri);
//        System.out.println("requestUri = " + requestUri);
        if (StringUtils.isNotEmpty(exludeUrlPattern)) {
            String[] exludeUrlPatternArr = exludeUrlPattern.split(",");
            for (String exludeUrl : exludeUrlPatternArr) {
                if (pathMatcher.match(exludeUrl, requestUri)) {
                    isExlude = true;
                    break;
                }
            }
        }

           /*
               过滤条件:
               1:在过滤路径规则下
               2:当前路径不是要排除的路径
               3:或当前不在过滤路径规则下，但是需要获取用户信息的
             */
        boolean filterFlag = false;
        /**
         * 是否需要登陆
         */
        boolean noLoginNeedUserFlag = false;
        try {
            //过滤规则下
            if (!isExlude && pathMatcher.match(protectUrlPattern, requestUri)) {
                filterFlag = true;
                //用来标记当前过滤器处理过，不能共用自带的alreadyFilteredAttributeName
                request.setAttribute(JwtAuthenticationFilter.class.getName() + JwtAuthenticationFilter.ALREADY_FILTERED_SUFFIX, true);
                request.setAttribute(JwtAuthenticationFilter.class.getName() + isNeedToken, true);
            }
            //要获取登录身份的
            if (CollectionUtils.isNotEmpty(noLoginNeedUserInfoList)) {
                if (noLoginNeedUserInfoList.contains(requestUri)) {
                    filterFlag = true;
                    noLoginNeedUserFlag = true;
                    request.setAttribute(JwtAuthenticationFilter.class.getName() + JwtAuthenticationFilter.ALREADY_FILTERED_SUFFIX, true);
                    request.setAttribute(JwtAuthenticationFilter.class.getName() + isNeedToken, false);
                } else {
                    //先全匹配找下，如果找不到再用ant表达式遍历找下
                    for (int i = 0; i < noLoginNeedUserInfoList.size(); i++) {
                        if (pathMatcher.match(noLoginNeedUserInfoList.get(i), requestUri)) {
                            filterFlag = true;
                            noLoginNeedUserFlag = true;
                            request.setAttribute(JwtAuthenticationFilter.class.getName() + JwtAuthenticationFilter.ALREADY_FILTERED_SUFFIX, true);
                            request.setAttribute(JwtAuthenticationFilter.class.getName() + isNeedToken, false);
                            break;
                        }
                    }
                }
            }
            if (filterFlag) {
                JwtUtil.setRedisDao(redisDao);
                request = JwtUtil.validateTokenAndAddUserIdToHeader(request, requestUri, noLoginNeedUserInfoList);
            }

        } catch (TokenValidationException e) {
//			response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
            //如果是不需要强制被拦截，但是根据登陆与否，有不同逻辑的，则不输出403
            if (!noLoginNeedUserFlag) {
                Result<String> result0 = ResultBuilder.buildResult(ErrorCode.code_403, e.getMessage());
                String json = JSONObject.toJSONString(result0, SerializerFeature.WriteDateUseDateFormat);
                response.setContentType(HttpConstant.contentTypeJsonUTF8);
                response.getWriter().write(json);
                response.getWriter().flush();
//            throw new ErrorCodeException(ErrorCode.code_403);
                return;
            }
        }
//        String name = this.getClass().getName();
        filterChain.doFilter(request, response);
    }

    public void setFilterStrategy(String filterStrategy) {
        this.filterStrategy = filterStrategy;
    }
}